package simplezap

import (
	"errors"
	"fmt"
	"io"
	"strings"
)

type Level int

const (
	LevelDebug Level = iota
	LevelInfo
	LevelWarn
	LevelError
)

func (l Level) String() string {
	switch l {
	case LevelDebug:
		return "DEBUG"
	case LevelInfo:
		return "INFO"
	case LevelWarn:
		return "WARN"
	case LevelError:
		return "ERROR"
	default:
		return "UNKNOWN"
	}
}

type Field struct {
	Key   string
	Value any
}

type Logger struct {
	writer io.Writer
	level  Level
}

func New(w io.Writer) *Logger {
	return &Logger{writer: w, level: LevelInfo}
}

func (l *Logger) SetLevel(level Level) {
	l.level = level
}

func (l *Logger) Debug(message string, fields ...Field) error {
	return l.log(LevelDebug, message, fields)
}

func (l *Logger) Info(message string, fields ...Field) error {
	return l.log(LevelInfo, message, fields)
}

func (l *Logger) Warn(message string, fields ...Field) error {
	return l.log(LevelWarn, message, fields)
}

func (l *Logger) Error(message string, fields ...Field) error {
	return l.log(LevelError, message, fields)
}

func (l *Logger) log(level Level, message string, fields []Field) error {
	if l == nil {
		return fmt.Errorf("logger is nil")
	}
	if l.writer == nil {
		return fmt.Errorf("writer is nil")
	}
	if level < l.level {
		return nil
	}

	payload := message
	if len(fields) > 0 {
		payload = fmt.Sprintf("%s | %s", message, formatFields(fields))
	}

	if _, err := fmt.Fprintf(l.writer, "[%s] %s\n", level.String(), payload); err != nil {
		return fmt.Errorf("write log: %w", err)
	}
	return nil
}

// Sugar 会返回一个“甜味”版本的 Logger，提供 Infow、Infof 等便捷 API。
func (l *Logger) Sugar() *SugaredLogger {
	return &SugaredLogger{base: l}
}

// SugaredLogger 包裹基础 Logger，用更加友好的参数形式写日志。
type SugaredLogger struct {
	base *Logger
}

func (s *SugaredLogger) Infow(message string, kv ...interface{}) error {
	fields, err := kvToFields(kv)
	if err != nil {
		return err
	}
	return s.base.Info(message, fields...)
}

func (s *SugaredLogger) Infof(format string, args ...interface{}) error {
	return s.base.Info(fmt.Sprintf(format, args...))
}

func (s *SugaredLogger) Debugw(message string, kv ...interface{}) error {
	fields, err := kvToFields(kv)
	if err != nil {
		return err
	}
	return s.base.Debug(message, fields...)
}

func (s *SugaredLogger) Debugf(format string, args ...interface{}) error {
	return s.base.Debug(fmt.Sprintf(format, args...))
}

func kvToFields(kv []interface{}) ([]Field, error) {
	if len(kv)%2 != 0 {
		return nil, errors.New("key-values must come in pairs")
	}
	fields := make([]Field, 0, len(kv)/2)
	for i := 0; i < len(kv); i += 2 {
		key, ok := kv[i].(string)
		if !ok {
			return nil, fmt.Errorf("key at position %d is not a string", i)
		}
		fields = append(fields, Field{Key: key, Value: kv[i+1]})
	}
	return fields, nil
}

func formatFields(fields []Field) string {
	parts := make([]string, 0, len(fields))
	for _, f := range fields {
		parts = append(parts, fmt.Sprintf("%s=%v", f.Key, f.Value))
	}
	return strings.Join(parts, ", ")
}
